import { UserInfo } from "./Cons";

export enum LogLevel {
    VERBOSE = 0,
    DEBUG = 1,
    INFO = 2,
    WARN = 3,
    ERROR = 4
}

// FIXME 获取用户设备信息
export class L {
    private static _level: LogLevel = LogLevel.DEBUG;
    private static _timeFormat: string = 'yyyy-mm-dd hh:MM:ss.SSS';
    private static _logQueue: any[] = [];
    private static _maxQueueSize: number = 50;
    private static _uploadUrl: string | null = null;
    private static _userInfo: UserInfo = {};
    private static _uploading: boolean = false;

    // 属性式访问器
    static get level(): LogLevel { return this._level; }
    static set level(value: LogLevel) { this._level = value; }

    static get timeFormat(): string { return this._timeFormat; }
    static set timeFormat(value: string) { this._timeFormat = value; }

    // 配置方法
    static configure(options: {
        maxQueueSize?: number;
        uploadUrl?: string;
        userInfo?: UserInfo;
    }): void {
        if (options.maxQueueSize !== undefined) {
            this._maxQueueSize = options.maxQueueSize;
        }
        if (options.uploadUrl !== undefined) {
            this._uploadUrl = options.uploadUrl;
        }
        if (options.userInfo !== undefined) {
            this._userInfo = { ...this._userInfo, ...options.userInfo };
        }
    }

    private static getFormattedTime(): string {
        const now = new Date();

        const pad = (num: number, length: number): string => {
            let str = num.toString();
            while (str.length < length) {
                str = '0' + str;
            }
            return str;
        };

        const year = now.getFullYear();
        const month = pad(now.getMonth() + 1, 2);
        const day = pad(now.getDate(), 2);
        const hours = pad(now.getHours(), 2);
        const minutes = pad(now.getMinutes(), 2);
        const seconds = pad(now.getSeconds(), 2);
        const milliseconds = pad(now.getMilliseconds(), 3);

        return this._timeFormat
            .replace('yyyy', year.toString())
            .replace('mm', month)
            .replace('dd', day)
            .replace('hh', hours)
            .replace('MM', minutes)
            .replace('ss', seconds)
            .replace('SSS', milliseconds);
    }

    private static async uploadLogs(): Promise<void> {
        if (this._uploading || !this._uploadUrl || this._logQueue.length === 0) {
            return;
        }

        this._uploading = true;
        const logsToUpload = [...this._logQueue];
        this._logQueue = [];

        try {
            const payload = {
                logs: logsToUpload,
                userInfo: this._userInfo,
                timestamp: new Date().toISOString()
            };

            await fetch(this._uploadUrl, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(payload),
            });
        } catch (error) {
            console.error('日志上传失败:', error);
            // 上传失败将日志放回队列
            this._logQueue.unshift(...logsToUpload);
        } finally {
            this._uploading = false;
        }
    }

    private static addToQueue(level: string, tag: string, ...args: any[]): void {
        if (this.level > LogLevel.INFO) return; // 只上传INFO及以上级别的日志

        this._logQueue.push({
            timestamp: new Date().toISOString(),
            level,
            tag,
            messages: args,
            localTime: this.getFormattedTime()
        });

        if (this._logQueue.length >= this._maxQueueSize) {
            this.uploadLogs();
        }
    }

    private static logInternal(level: string, levelNum: LogLevel, levelColor: string, tag: string, ...args: any[]): void {
        const timeStr = this.getFormattedTime();
        const formattedTag = `%c[${timeStr}][${level}][TAG=${tag}]`;
        const style = `color: ${levelColor};`;

        // 根据日志级别选择对应的 console 方法
        switch (levelNum) {
            case LogLevel.ERROR:
                console.error(formattedTag, style, ...args);
                break;
            case LogLevel.WARN:
                console.warn(formattedTag, style, ...args);
                break;
            case LogLevel.INFO:
                console.info(formattedTag, style, ...args);
                break;
            case LogLevel.DEBUG:
                console.debug(formattedTag, style, ...args);
                break;
            case LogLevel.VERBOSE:
            default:
                console.log(formattedTag, style, ...args);
        }

        if (levelNum >= this.level) {
            this.addToQueue(level, tag, ...args);
        }
    }

    // 兼容 console 的重载方法
    // Log
    static log(...args: any[]): void;
    static log(tag: string, ...args: any[]): void;
    static log(arg1: any, ...args: any[]): void {
        const [tag, actualArgs] = this.parseArgs(arg1, args);
        this.logInternal('INFO', LogLevel.INFO, '#00a', tag, ...actualArgs);
    }

    // Verbose
    static verbose(...args: any[]): void;
    static verbose(tag: string, ...args: any[]): void;
    static verbose(arg1: any, ...args: any[]): void {
        const [tag, actualArgs] = this.parseArgs(arg1, args);
        this.logInternal('VERBOSE', LogLevel.VERBOSE, '#888', tag, ...actualArgs);
    }

    // Debug
    static debug(...args: any[]): void;
    static debug(tag: string, ...args: any[]): void;
    static debug(arg1: any, ...args: any[]): void {
        const [tag, actualArgs] = this.parseArgs(arg1, args);
        this.logInternal('DEBUG', LogLevel.DEBUG, '#0a0', tag, ...actualArgs);
    }

    // Info
    static info(...args: any[]): void;
    static info(tag: string, ...args: any[]): void;
    static info(arg1: any, ...args: any[]): void {
        const [tag, actualArgs] = this.parseArgs(arg1, args);
        this.logInternal('INFO', LogLevel.INFO, '#00a', tag, ...actualArgs);
    }

    // Warn
    static warn(...args: any[]): void;
    static warn(tag: string, ...args: any[]): void;
    static warn(arg1: any, ...args: any[]): void {
        const [tag, actualArgs] = this.parseArgs(arg1, args);
        this.logInternal('WARN', LogLevel.WARN, '#fa0', tag, ...actualArgs);
    }

    // Error
    static error(...args: any[]): void;
    static error(tag: string, ...args: any[]): void;
    static error(arg1: any, ...args: any[]): void {
        const [tag, actualArgs] = this.parseArgs(arg1, args);
        this.logInternal('ERROR', LogLevel.ERROR, '#f00', tag, ...actualArgs);
    }
    // 提取公共参数解析逻辑
    private static parseArgs(arg1: any, args: any[]): [string, any[]] {
    // 情况1：第一个参数是字符串且第二个参数存在 -> 作为tag
    if (typeof arg1 === 'string' && args.length > 0) {
        return [arg1, args];
    }
    // 情况2：任何单参数情况 -> 作为消息内容
    return ['', args.length === 0 ? [arg1] : [arg1, ...args]];
}

    // 手动触发上传
    static flush(): Promise<void> {
        return this.uploadLogs();
    }
}